//#include <QCoreApplication>

#include <iostream>
#include <istream>
#include <fstream>
#include <condition_variable>
#include <thread>
#include <chrono>


using namespace std;

std::condition_variable         cv      ;
std::mutex                      cv_m       ;
//std::unique_lock<std::mutex>    lk(m)   ;
int i = 0;

void waits()
{
    {
        std::unique_lock<std::mutex> lk(cv_m);
        std::cerr << "Waiting...\n";
        std::thread::id threadId = this_thread::get_id();
        std::cout << "threadId: " << threadId << endl;
        cv.wait(lk, []{return i == 1;});
    }
    std::cerr << "... finished waiting. i == 1\n";
}

void signals_test()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::thread::id threadId = this_thread::get_id();
        std::cout << "signal test threadId: " << threadId << endl;
        std::cerr << "Notifying ...\n";
    }

    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main(int argc, char *argv[])
{
    std::thread thread1(waits);
    std::thread thread2(waits);
    std::thread thread3(waits);
    std::thread thread4(signals_test);

    thread1.join();
    thread2.join();
    thread3.join();
    thread4.join();

    return 0;
}


//#include <iostream>
//#include <string>
//#include <thread>
//#include <mutex>
//#include <condition_variable>
//#include <chrono>

//std::mutex m;
//std::condition_variable cv;
//std::string data;
//bool ready = false;
//bool processed = false;

//void worker_thread()
//{
//    // Wait until main() sends data
//    std::unique_lock<std::mutex> lk(m);
//    cv.wait(lk, []{return ready;});

//    // after the wait, we own the lock.
//    std::cout << "Worker thread is processing data\n";
//    data += " after processing";

//    // Send data back to main()
//    processed = true;
//    std::cout << "Worker thread signals data processing completed\n";

//    // Manual unlocking is done before notifying, to avoid waking up
//    // the waiting thread only to block again (see notify_one for details)
//    lk.unlock();
//    cv.notify_one();
//}

//int main()
//{
//    data = "Example data";
//    // send data to the worker thread
//    {
////        std::lock_guard<std::mutex> lk(m);
//        std::unique_lock<std::mutex> lk(m);
//        ready = true;
//        std::cout << "main() signals data ready for processing\n";
//    }
////    processed = true;
//    cv.notify_one();

//    std::cout << "out send data\n";

//    // wait for the worker
//    {
//        std::cout << "test code: \n";
//        std::unique_lock<std::mutex> lk(m);
//        std::cout << "test code*: \n";
//        std::cout << "test code*: \n";
//        std::cout << "test code*: \n";
////        cv.wait(lk, []{return processed;});
//        cv.wait_for(lk, 200, []{return processed;});
//    }
//    std::cout << "Back in main(), data = " << data << '\n';

//    std::thread worker(worker_thread);

//    worker.join();
//}


//#include <iostream>
//#include <string>
//#include <thread>
//#include <mutex>
//#include <condition_variable>

//std::mutex m;
//std::condition_variable cv;
//std::string data;
//bool ready = false;
//bool processed = false;

//void worker_thread()
//{
//    // Wait until main() sends data
//    std::unique_lock<std::mutex> lk(m);
//    cv.wait(lk, []{return ready;});

//    // after the wait, we own the lock.
//    std::cout << "Worker thread is processing data\n";
//    data += " after processing";

//    // Send data back to main()
//    processed = true;
//    std::cout << "Worker thread signals data processing completed\n";

//    // Manual unlocking is done before notifying, to avoid waking up
//    // the waiting thread only to block again (see notify_one for details)
//    lk.unlock();
//    cv.notify_one();
//}

//void SendThread(std::string str, bool readyFlag) {
//    std::string tempStr = "Example data";
//    {
//        std::lock_guard<std::mutex> lk(m);
//        for(int i = 0; i < tempStr.size(); ++i) {
//            data += tempStr[i];
//        }
//        ready = readyFlag;
//    }
//    cv.notify_one();
//}

//void WaitThread()
//{
//    {
//        std::unique_lock<std::mutex> lk(m);
//        cv.wait(lk, []{return processed;});
//    }
//    std::cout << "Back in main(), data = " << data << '\n';
//}


//int main()
//{
//    std::thread worker(worker_thread);
////    std::thread Sender(SendThread, )

////    data = "Example data";
////    // send data to the worker thread
////    {
////        std::lock_guard<std::mutex> lk(m);
////        ready = true;
////        std::cout << "main() signals data ready for processing\n";
////    }
////    cv.notify_one();

//    // wait for the worker
////    {
////        std::unique_lock<std::mutex> lk(m);
////        cv.wait(lk, []{return processed;});
////    }
////    std::cout << "Back in main(), data = " << data << '\n';

//    worker.join();
//}
